diff -rcNP linux/Documentation/admin-guide/sysctl/kernel.rst ipc/Documentation/admin-guide/sysctl/kernel.rst
*** linux/Documentation/admin-guide/sysctl/kernel.rst	2021-02-24 11:30:42.253000000 -0500
--- ipc/Documentation/admin-guide/sysctl/kernel.rst	2021-02-24 15:56:41.302000000 -0500
***************
*** 283,288 ****
--- 283,311 ----
  default value of dmesg_restrict.
  
  
+ harden_ipc
+ ==========
+ 
+ This toggle indicates whether access to overly-permissive IPC objects
+ is disallowed.
+ 
+ If harden_ipc is set to (0), there are no restrictions. If harden_ipc
+ is set to (1), access to overly-permissive IPC objects (shared
+ memory, message queues, and semaphores) will be denied for processes
+ given the following criteria beyond normal permission checks:
+ 1) If the IPC object is world-accessible and the euid doesn't match
+   that of the creator or current uid for the IPC object
+ 2) If the IPC object is group-accessible and the egid doesn't
+   match that of the creator or current gid for the IPC object
+ It's a common error to grant too much permission to these objects,
+ with impact ranging from denial of service and information leaking to
+ privilege escalation. This feature was developed in response to
+ research by Tim Brown:
+ http://labs.portcullis.co.uk/whitepapers/memory-squatting-attacks-on-system-v-shared-memory/
+ who found hundreds of such insecure usages. Processes with
+ CAP_IPC_OWNER are still permitted to access these IPC objects.
+ 
+ 
  domainname & hostname:
  ======================
  
diff -rcNP linux/include/linux/ipc.h ipc/include/linux/ipc.h
*** linux/include/linux/ipc.h	2021-02-23 09:02:26.000000000 -0500
--- ipc/include/linux/ipc.h	2021-02-24 15:57:28.815000000 -0500
***************
*** 8,13 ****
--- 8,15 ----
  #include <uapi/linux/ipc.h>
  #include <linux/refcount.h>
  
+ extern int harden_ipc;
+ 
  /* used by in-kernel data structures */
  struct kern_ipc_perm {
  	spinlock_t	lock;
diff -rcNP linux/ipc/harden_ipc.c ipc/ipc/harden_ipc.c
*** linux/ipc/harden_ipc.c	1969-12-31 19:00:00.000000000 -0500
--- ipc/ipc/harden_ipc.c	2021-02-24 15:59:45.029000000 -0500
***************
*** 0 ****
--- 1,46 ----
+ #include <linux/kernel.h>
+ #include <linux/mm.h>
+ #include <linux/sched.h>
+ #include <linux/file.h>
+ #include <linux/ipc.h>
+ #include <linux/ipc_namespace.h>
+ #include <linux/cred.h>
+ 
+ int harden_ipc __read_mostly = IS_ENABLED(CONFIG_SECURITY_HARDEN_IPC);
+ 
+ int
+ ipc_permitted(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, int requested_mode, int granted_mode)
+ {
+ 	int write;
+ 	int orig_granted_mode;
+ 	kuid_t euid;
+ 	kgid_t egid;
+ 
+ 	if (!harden_ipc)
+ 		return 1;
+ 
+ 	euid = current_euid();
+ 	egid = current_egid();
+ 
+ 	write = requested_mode & 00002;
+ 	orig_granted_mode = ipcp->mode;
+ 
+ 	if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid))
+ 		orig_granted_mode >>= 6;
+ 	else {
+ 		/* if likely wrong permissions, lock to user */
+ 		if (orig_granted_mode & 0007)
+ 			orig_granted_mode = 0;
+ 		/* otherwise do a egid-only check */
+ 		else if (gid_eq(egid, ipcp->cgid) || gid_eq(egid, ipcp->gid))
+ 			orig_granted_mode >>= 3;
+ 		/* otherwise, no access */
+ 		else
+ 			orig_granted_mode = 0;
+ 	}
+ 	if (!(requested_mode & ~granted_mode & 0007) && (requested_mode & ~orig_granted_mode & 0007) &&
+ 	    !ns_capable_noaudit(ns->user_ns, CAP_IPC_OWNER)) {
+ 		return 0;
+ 	}
+ 	return 1;
+ }
diff -rcNP linux/ipc/Makefile ipc/ipc/Makefile
*** linux/ipc/Makefile	2021-02-23 09:02:26.000000000 -0500
--- ipc/ipc/Makefile	2021-02-24 16:01:14.313000000 -0500
***************
*** 4,12 ****
  #
  
  obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
! obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o
  obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o
  obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o
  obj-$(CONFIG_IPC_NS) += namespace.o
  obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o
- 
--- 4,11 ----
  #
  
  obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
! obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o harden_ipc.o
  obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o
  obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o
  obj-$(CONFIG_IPC_NS) += namespace.o
  obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o
diff -rcNP linux/ipc/util.c ipc/ipc/util.c
*** linux/ipc/util.c	2021-02-23 09:02:26.000000000 -0500
--- ipc/ipc/util.c	2021-02-24 16:02:24.916000000 -0500
***************
*** 76,81 ****
--- 76,83 ----
  	int (*show)(struct seq_file *, void *);
  };
  
+ extern int ipc_permitted(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, int requested_mode, int granted_mode);
+ 
  /**
   * ipc_init - initialise ipc subsystem
   *
***************
*** 529,534 ****
--- 531,540 ----
  		granted_mode >>= 6;
  	else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
  		granted_mode >>= 3;
+ 
+ 	if (!ipc_permitted(ns, ipcp, requested_mode, granted_mode))
+ 		return -1;
+ 
  	/* is there some bit set in requested_mode but not in granted_mode? */
  	if ((requested_mode & ~granted_mode & 0007) &&
  	    !ns_capable(ns->user_ns, CAP_IPC_OWNER))
diff -rcNP linux/kernel/sysctl.c ipc/kernel/sysctl.c
*** linux/kernel/sysctl.c	2021-02-24 11:30:42.279000000 -0500
--- ipc/kernel/sysctl.c	2021-02-24 16:03:28.137000000 -0500
***************
*** 68,73 ****
--- 68,74 ----
  #include <linux/bpf.h>
  #include <linux/mount.h>
  #include <linux/userfaultfd_k.h>
+ #include <linux/ipc.h>
  
  #include "../lib/kstrtox.h"
  
***************
*** 935,940 ****
--- 936,952 ----
  		.extra1		= SYSCTL_ZERO,
  		.extra2		= SYSCTL_ONE,
  	},
+ #ifdef CONFIG_SYSVIPC
+ 	{
+ 		.procname	= "harden_ipc",
+ 		.data		= &harden_ipc,
+ 		.maxlen		= sizeof(int),
+ 		.mode		= 0644,
+ 		.proc_handler	= &proc_dointvec_minmax_sysadmin,
+ 		.extra1		= SYSCTL_ZERO,
+ 		.extra2		= SYSCTL_ONE,
+ 	},
+ #endif
  	{
  		.procname	= "ngroups_max",
  		.data		= &ngroups_max,
diff -rcNP linux/security/Kconfig ipc/security/Kconfig
*** linux/security/Kconfig	2021-02-24 11:30:42.289000000 -0500
--- ipc/security/Kconfig	2021-02-24 16:05:10.104000000 -0500
***************
*** 61,66 ****
--- 61,91 ----
  	bool
  	default n
  
+ config SECURITY_HARDEN_IPC
+ 			bool "Disallow access to overly-permissive IPC objects"
+ 			default y
+ 			depends on SYSVIPC
+ 			help
+ 			  If you say Y here, access to overly-permissive IPC objects (shared
+ 			  memory, message queues, and semaphores) will be denied for processes
+ 			  given the following criteria beyond normal permission checks:
+ 			  1) If the IPC object is world-accessible and the euid doesn't match
+ 			     that of the creator or current uid for the IPC object
+ 			  2) If the IPC object is group-accessible and the egid doesn't
+ 			     match that of the creator or current gid for the IPC object
+ 			  It's a common error to grant too much permission to these objects,
+ 			  with impact ranging from denial of service and information leaking to
+ 			  privilege escalation.  This feature was developed in response to
+ 			  research by Tim Brown:
+ 			  http://labs.portcullis.co.uk/whitepapers/memory-squatting-attacks-on-system-v-shared-memory/
+ 			  who found hundreds of such insecure usages. Processes with
+ 			  CAP_IPC_OWNER are still permitted to access these IPC objects.
+ 
+ 				This setting can be overridden at runtime via the kernel.harden_ipc
+ 			  sysctl.
+ 
+ 			  If unsure, say Y.
+ 
  config SECURITYFS
  	bool "Enable the securityfs filesystem"
  	help
